﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using log4net.Repository.Hierarchy;

namespace Version2
{
    /// <summary>
    /// This purpose of this class it too keep track of that last search results in order
    /// that a new search request may be optimizied. This will cut down on the amount of times
    /// we ping twitter so that we don't get locked out and waste time.
    /// </summary>
    public class TwitterSearchMetadata
    {
        private SocialDataPoint oldestPoint = null;
        private SocialDataPoint newestPoint = null;
        private SearchParameters lastParams = null;
        private ILog logger = LogManager.GetLogger(typeof(TwitterSearchMetadata));
        private Dictionary<DateTime, ulong> maxIdForDay = new Dictionary<DateTime,ulong>();

        /// <summary>
        /// Should check times and radius to see if new search falls within bounds of previous
        /// search. If so, the caller knows to return the same dataset. If not, a new search
        /// should be performed.
        /// </summary>
        /// <param name="prms"></param>
        /// <returns></returns>
        public Boolean canReturnSameData(SearchParameters prms)
        {
            if (oldestPoint == null || newestPoint == null)
                return false;
            if (lastParams == null)
                return false;
            if (prms.Radius > lastParams.Radius || prms.Address != lastParams.Address ||
                prms.Latitude != lastParams.Latitude || prms.Longitude != lastParams.Longitude)
                return false;

            DateTime windowFurthest = prms.DateAndTime.AddMinutes(-prms.MinutesBeforeAndAfter).ToLocalTime();
            DateTime windowNearest = prms.DateAndTime.AddMinutes(prms.MinutesBeforeAndAfter).ToLocalTime();
            if (windowNearest > DateTime.Now)
                windowNearest = DateTime.Now;

            if (windowFurthest >= oldestPoint.BirthDate &&
                windowNearest <= newestPoint.BirthDate)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// If radius is same, but window has been increased, may be able to just pick up
        /// where we left off.
        /// </summary>
        /// <param name="sp"></param>
        /// <returns></returns>
        public SuggestedWindows idToStartFrom(SearchParameters sp)
        {
            logger.Debug("Using untested method! TwitterSearchMetadata.idToStartFrom");
            SuggestedWindows windows = new SuggestedWindows();
            if (sp.Radius > lastParams.Radius || sp.Address != lastParams.Address ||
                sp.Latitude != lastParams.Latitude || sp.Longitude != lastParams.Longitude)
                return windows;

            DateTime windowFurthest = sp.DateAndTime.AddMinutes(-sp.MinutesBeforeAndAfter).ToLocalTime();
            DateTime windowNearest = sp.DateAndTime.AddMinutes(sp.MinutesBeforeAndAfter).ToLocalTime();

            // If the +min is beyond current time, set recent to max.
            if (windowNearest >= DateTime.Now)
                windows.RecentMaxId = ulong.MaxValue;

            // If upper bound on window is still within our data's range. Ensure we don't ask for anything newer.
            if (windowNearest < newestPoint.BirthDate)
                windows.RecentMaxId = newestPoint.Id;

            // If our recent window bound is greater than most recent data, only go back to most recent.
            if (windowNearest > newestPoint.BirthDate)
            {
                windows.RecentMinId = newestPoint.Id;
            }

            // If we simply must look back further.
            if (windowFurthest < oldestPoint.BirthDate)
                windows.OldMaxId = oldestPoint.Id;

            // If we are not even outside our previous retrieved data, make sure we don't try to search old data.
            if (windowFurthest > oldestPoint.BirthDate)
                windows.OldMinId = oldestPoint.Id;

            return windows;
        }

        /// <summary>
        /// If a search is performed, this method should be called for future optimization.
        /// </summary>
        /// <param name="sp"></param>
        /// <param name="oldest"></param>
        /// <param name="newest"></param>
        public void updateLastSearchMetadata(SearchParameters sp, SocialDataPoint oldest, SocialDataPoint newest)
        {
            oldestPoint = oldest;
            newestPoint = newest;
            lastParams = new SearchParameters(sp);
        }

        /// <summary>
        /// The idea behind this method placeholder is that if we ask for info around 00:30 on a given day,
        /// Twitter naturall starts at 23:59 and pages backwards until hitting the right time. This could 
        /// take 20 or 30 searches and wast time. Rather, we can wisen up and do short searches to find
        /// Max and Min status id's and guesstimate appropriate windows.
        /// </summary>
        /// <param name="sp"></param>
        public ulong findWindowForSearch(SearchParameters sp)
        {
            logger.Debug("Returning max value for window to search.");
            DateTime max = sp.DateAndTime.Date;

            // Find max id for a given date.

            // Find max id for day before.

            // estimate Max/Min ids for twitter search.
            return ulong.MaxValue;
        }
    }
    public class SuggestedWindows
    {
        public SuggestedWindows()
        {
            RecentMaxId = ulong.MaxValue;
            RecentMinId = 0;
            OldMaxId = 0;
            OldMinId = 0;
        }
        public ulong RecentMinId { get; set; }
        public ulong RecentMaxId { get; set; }
        public ulong OldMinId { get; set; }
        public ulong OldMaxId { get; set; }
    }
}
